﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Input;

namespace Kokomo.Controls
{
	public class LayoutHandle : ContentControl
	{
		static LayoutHandle()
		{
			DefaultStyleKeyProperty.OverrideMetadata(typeof(LayoutHandle), new FrameworkPropertyMetadata(typeof(LayoutHandle)));
		}
		public LayoutHandle()
		{
		}

		#region Resizable
		public static bool GetResizable(DependencyObject obj)
		{
			return (bool)obj.GetValue(ResizableProperty);
		}

		public static void SetResizable(DependencyObject obj, bool value)
		{
			obj.SetValue(ResizableProperty, value);
		}

		// Using a DependencyProperty as the backing store for Resizable.  This enables animation, styling, binding, etc...
		public static readonly DependencyProperty ResizableProperty =
			DependencyProperty.RegisterAttached("Resizable", typeof(bool), typeof(LayoutHandle), new UIPropertyMetadata(false));
		#endregion
		#region IsTargetResizable
		//private bool _isTargetResizable;
		//public bool IsTargetResizable
		//{
		//    get { return this._isTargetResizable; }
		//    private set
		//    {
		//        this._isTargetResizable = value;
		//    }
		//}



		public bool IsTargetResizable
		{
			get { return (bool)GetValue(IsTargetResizableProperty); }
			private set { SetValue(IsTargetResizablePropertyKey, value); }
		}

		// Using a DependencyProperty as the backing store for IsTargetResizable.  This enables animation, styling, binding, etc...
		private static readonly DependencyPropertyKey IsTargetResizablePropertyKey =
			DependencyProperty.RegisterReadOnly("IsTargetResizable", typeof(bool), typeof(LayoutHandle), new UIPropertyMetadata(false));

		public static readonly DependencyProperty IsTargetResizableProperty = IsTargetResizablePropertyKey.DependencyProperty;

		private void ComputeIsTargetResizable()
		{
			FrameworkElement target = this.ActualResizeTarget;
			this.IsTargetResizable =
				(target != null) && GetResizable(target);
		}
		#endregion

		#region ResizeTarget
		public FrameworkElement LayoutTarget
		{
			get { return (FrameworkElement)GetValue(LayoutTargetProperty); }
			set { SetValue(LayoutTargetProperty, value); }
		}

		// Using a DependencyProperty as the backing store for ResizeTarget.  This enables animation, styling, binding, etc...
		public static readonly DependencyProperty LayoutTargetProperty =
			DependencyProperty.Register("LayoutTarget", typeof(FrameworkElement), typeof(LayoutHandle), new UIPropertyMetadata(null, OnLayoutTargetChanged));

		private static void OnLayoutTargetChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
		{
			((LayoutHandle)target).OnLayoutTargetChanged();
		}
		protected virtual void OnLayoutTargetChanged()
		{
			this.ComputeIsTargetResizable();
		}
		#endregion
		#region Behavior
		public LayoutHandleBehavior Behavior
		{
			get { return (LayoutHandleBehavior)GetValue(BehaviorProperty); }
			set { SetValue(BehaviorProperty, value); }
		}

		// Using a DependencyProperty as the backing store for Behavior.  This enables animation, styling, binding, etc...
		public static readonly DependencyProperty BehaviorProperty =
			DependencyProperty.Register("Behavior", typeof(LayoutHandleBehavior), typeof(LayoutHandle), new UIPropertyMetadata(LayoutHandleBehavior.None));
		#endregion

		public FrameworkElement ActualResizeTarget
		{
			get
			{
				return this.LayoutTarget ?? (this.TemplatedParent as FrameworkElement);
			}
		}

		protected override void OnVisualParentChanged(DependencyObject oldParent)
		{
			base.OnVisualParentChanged(oldParent);

			this.ComputeIsTargetResizable();
		}

		#region Mouse
		private Point? _mouseDownLocation;

		protected override void OnMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e)
		{
			this._mouseDownLocation = e.GetPosition(this);
			this.CaptureMouse();

			e.Handled = true;
		}

		protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e)
		{
			FrameworkElement resizeTarget = this.ActualResizeTarget;
			if (resizeTarget == null) return;
			if (!this.IsTargetResizable) return;

			Point? mouseDownLocation = this._mouseDownLocation;
			if (!mouseDownLocation.HasValue) return;

			Point newLocation = e.GetPosition(this);

			double dx = newLocation.X - mouseDownLocation.Value.X;
			double dy = newLocation.Y - mouseDownLocation.Value.Y;

			double left = Canvas.GetLeft(resizeTarget);
			if (double.IsNaN(left)) left = 0;
			double top = Canvas.GetTop(resizeTarget);
			if (double.IsNaN(top)) top = 0;
			double width = resizeTarget.Width;
			if (double.IsNaN(width)) width = resizeTarget.RenderSize.Width;
			double height = resizeTarget.Height;
			if (double.IsNaN(height)) height = resizeTarget.RenderSize.Height;

			double? newWidth = null;
			double? newHeight = null;

			switch (this.Behavior)
			{
				case LayoutHandleBehavior.TopLeft:
					resizeTarget.SetValue(Canvas.LeftProperty, left + dx);
					resizeTarget.SetValue(Canvas.TopProperty, top + dy);
					newWidth = width - dx;
					newHeight = height - dy;
					break;
				case LayoutHandleBehavior.Top:
					resizeTarget.SetValue(Canvas.TopProperty, top + dy);
					newHeight = height - dy;
					break;
				case LayoutHandleBehavior.TopRight:
					resizeTarget.SetValue(Canvas.TopProperty, top + dy);
					newWidth = width + dx;
					newHeight = height - dy;
					break;
				case LayoutHandleBehavior.Left:
					resizeTarget.SetValue(Canvas.LeftProperty, left + dx);
					newWidth = width - dx;
					break;
				case LayoutHandleBehavior.Right:
					newWidth = width + dx;
					break;
				case LayoutHandleBehavior.BottomLeft:
					resizeTarget.SetValue(Canvas.LeftProperty, left + dx);
					newWidth = width - dx;
					newHeight = height + dy;
					break;
				case LayoutHandleBehavior.Bottom:
					newHeight = height + dy;
					break;
				case LayoutHandleBehavior.BottomRight:
					newWidth = width + dx;
					newHeight = height + dy;
					break;
				case LayoutHandleBehavior.Move:
					resizeTarget.SetValue(Canvas.LeftProperty, left + dx);
					resizeTarget.SetValue(Canvas.TopProperty, top + dy);
					break;
			}

			if (newWidth.HasValue)
				resizeTarget.Width = Math.Max(0, newWidth.Value);
			if (newHeight.HasValue)
				resizeTarget.Height = Math.Max(0, newHeight.Value);
		}

		protected override void OnMouseLeftButtonUp(System.Windows.Input.MouseButtonEventArgs e)
		{
			this._mouseDownLocation = null;
			this.ReleaseMouseCapture();
			e.Handled = true;
		}
		#endregion
	}
}
